#include "wl_trace.h"

#include "wl_core.h"
#include "wl_message_queue.h"
#include "wl_utils.h"

#include <string.h>

#define TRACE_BUF_SIZE 255

#if defined(WL_OS_MG)
#    define CUR_WLLOG_LEVEL WLLOG_DEBUG_LEVEL
#elif defined(WL_OS_U8910)
#    include <os_api.h>
#    include <sci_log.h>
#    define CUR_WLLOG_LEVEL WLLOG_DEBUG_LEVEL
#elif defined(WL_OS_QUECTEL)
#    include "ql_rtos.h"
#    define CUR_WLLOG_LEVEL WLLOG_ERROR_LEVEL
#else
#    define CUR_WLLOG_LEVEL WLLOG_WARN_LEVEL
#    define TRACE_BUF_SIZE 511
#endif

// #define OSAL_DEBUG

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

static wl_trace_callback s_trace_callback                        = wl_null;
static wl_char           s_trace_level_name[WLLOG_LEVEL_MAX][10] = {"TRACE", "INFO", "DEBUG", "WARN", "ERROR"};
static wl_bool           s_trace_is_open                         = wl_false;
static wl_uint32         s_trace_level                           = WLLOG_ERROR_LEVEL;

#ifdef OSAL_DEBUG
static wl_bool          s_trace_init = wl_false;
static WL_MESSAGE_QUEUE s_trace_queue;
static wl_bool          s_trace_start = wl_false;
#endif

#ifdef OSAL_DEBUG
#    if defined(WL_OS_QUECTEL)
void trace_main_thread(void* param) {
    wl_char trace[TRACE_BUF_SIZE];
    WLLOGT("trace_main_thread");
    s_trace_start = wl_true;
    while (s_trace_init) {
        if (0 == wl_message_queue_receive(&s_trace_queue, (void*)trace, TRACE_BUF_SIZE)) {
            if (s_trace_callback) {
                s_trace_callback((wl_char*)trace);
            }
        } else {
            wl_msleep(500);
        }
    }
}

void trace_task_create(void) {
    if (!s_trace_init) {
        if (-1 == wl_message_queue_create("trace_queue", &s_trace_queue, 50, 256)) {
            WLLOGW("wl_message_queue_create trace queue fail");
            return -1;
        }
        s_trace_init = wl_true;
        // 启动日志线程,解决卡顿问题
        ql_task_t thread;
        if (0 != ql_rtos_task_create(&thread, 8 * 1024, 100, "wl_trace", trace_main_thread, wl_null)) {
            WLLOGW("ql_rtos_task_create trace fail");
            s_trace_init = wl_false;
            return;
        }
    }
}
#    endif
#endif

void wl_trace_regist_callback(wl_trace_callback callback) {
    s_trace_callback = callback;
#ifdef OSAL_DEBUG
    trace_task_create();
#endif
}

void trace_async_callback(wl_char* buf) {
#ifdef OSAL_DEBUG
    if (s_trace_start) {
        if (0 != wl_message_queue_send(&s_trace_queue, buf, TRACE_BUF_SIZE)) {
            return -1;
        }
    } else {
        if (s_trace_callback) {
            s_trace_callback(buf);
        }
    }
#else
    if (s_trace_callback) {
        s_trace_callback(buf);
    }
#endif
}

void wl_trace_config(wl_bool isopen, wl_uint32 level) {
#if defined(WL_OS_MG) || defined(WL_OS_U8910) || defined(WL_OS_QUECTEL)
    s_trace_is_open = isopen;
    s_trace_level   = level;
#else
    s_trace_is_open = isopen;
    s_trace_level   = level;
#endif
}

wl_bool wl_trace_is_open(void) {
    return s_trace_is_open;
}

void wl_trace(wl_int32 level, const wl_char* format, ...) {
    if (s_trace_is_open && level >= s_trace_level && level < WLLOG_LEVEL_MAX && wl_null != s_trace_callback) {
        va_list  va;
        wl_char  buf[TRACE_BUF_SIZE + 1] = "";
        wl_int32 buflen                  = 0;

        sprintf(buf, "[%d][%d][WLSDK][%s]:", wl_utctime(), wl_getElapsedTick(), s_trace_level_name[level]);
        buflen = strlen(buf);

        va_start(va, format);
#if defined(WL_OS_MG)
#elif defined(WL_OS_U8910)
        _vsnprintf(buf + buflen, TRACE_BUF_SIZE - buflen, format, va);
#elif defined(WL_OS_QUECTEL)
        vsnprintf(buf + buflen, TRACE_BUF_SIZE - buflen, format, va);
#else
        vsnprintf(buf + buflen, TRACE_BUF_SIZE - buflen, format, va);
#endif
        va_end(va);
        buf[TRACE_BUF_SIZE] = '\0';
        trace_async_callback(buf);
    }
}

int wl_trace_weilapb(const wl_char* format, ...) {
    va_list  va;
    wl_char  buf[TRACE_BUF_SIZE + 1] = "";
    wl_int32 buflen                  = 0;

    sprintf(buf, "[%d][%d][WLSDK][ERROR]:", wl_utctime(), wl_getElapsedTick());
    buflen = strlen(buf);

    va_start(va, format);
#if defined(WL_OS_MG)
#elif defined(WL_OS_U8910)
    _vsnprintf(buf + buflen, TRACE_BUF_SIZE - buflen, format, va);
#elif defined(WL_OS_QUECTEL)
    vsnprintf(buf + buflen, TRACE_BUF_SIZE - buflen, format, va);
#else
    vsnprintf(buf + buflen, TRACE_BUF_SIZE - buflen, format, va);
#endif
    va_end(va);
    buf[TRACE_BUF_SIZE] = '\0';
    trace_async_callback(buf);
    return 0;
}

#ifdef __cplusplus
}
#endif /* __cplusplus */
